网易云IM云服务的稳定原来是这样实现的
你们都知道,我们网易云的IM云服务是卖得很火的。
人红压力大,为了能给百万商家亿级终端用户提供便捷的即时通信服务,保证我们的业务系统能承受住各种大压力的考验,如何保障系统的稳定运行,支撑更大的并发,提供真正的可扩展的IM云服务是一个很重要的问题。
这个问题,网易云首席DBA、网易资深数据运维工程师在上周一次分享中是这样说的:
●●●
分布式数据库架构介绍
作为互联网的一支老牌劲旅,我们在大并发海量互联网系统构建方面也有着非常深厚的积累与经验。在数据库选择上我们使用了网易私有云中的分布式数据库服务(云DDB),其架构图如下:
云DDB主要包括五个组件: NLB、SQL Proxy、DBN、Master、SYSDB。
NLB是负载均衡服务,基于LVS打造,负责将应用请求转发到后端SQL Proxy, 同时定时检测后端SQL Proxy的可用性,及时将故障机器从集群中摘除。
SQL Proxy实现了MySQL协议,接收客户端请求,同时负责将请求路由到具体的后端数据库节点,并返回数据给客户端。如果数据请求分布在多个节点,则可能使用2PC协议进行分布式事务(保障数据一致性)。
DBN则是底层真正负责数据存取的服务,通常是一个关系型数据库,目前支持MySQL、Oracle。
Master是管理服务,负责管理集群,比如新建表、设置数据路由策略、设置客户端连接池参数、DBN切换、配置变更通知等,操作结果(集群元数据)将持久化到SYSDB。
SYSDB是一个数据库,负责存储分布式数据库的元数据信息,包括表、字段、权限、数据路由等信息。
DBN与SYSDB使用的是网易私有云RDS,其它组件则部署在使用云主机上,云DDB服务的核心组件SQL Proxy以及DBN都是可扩展的,并且高可用的。
DDB处理逻辑简单来说就是应用请求通过NLB转发到具体SQL Proxy上,SQL Proxy解析SQL生成执行计划,下发请求至底层节点,收到DBN数据后做一定的处理返回给客户端。
●●●
高可用分布式DB服务构建指南
网易IM云服务目标是支持弹性扩展、消息必达,那就需要在保证高吞吐、高性能的同时,那就需要数据的高可用性:简单而言就是数据存储服务要高可用并且数据不丢失。
因为关系型数据库发展几十年在稳定性方面对比其他数据存储方案来说存在非常大的优势,基于此,业务很多对数据一致性的场景都是直接依赖于DB。
比如为了保证消息准确到达,发送方的消息需要先持久化到DB,再发送到接收方,接收方收到之后更新为已接收状态,因此对数据库是重度依赖。
对关系型数据库来说高性能高可用跟数据不丢失又往往是鱼跟熊掌的关系,要保证数据完全不丢失的话,数据必然是要同时写入到主库与从库才算完成,此时如果从机异常,数据写入将失败,这将导致数据库服务不可用,相信很少有人能接受。
所以通常在数据一致性与服务可用性上会做一定的妥协,即正常情况下表现为主从强一致性模式,异常情况下则退化为异步模式。这在MySQL里面我们称之为Semi sync复制,Oracle 复制(DataGuard) 里面则为最大保护模式。
在保证数据服务高性高吞吐的情况下尽量避免数据丢失,我们对网易云DDB底层DBN做了如下设置:
将sync_binlog与innodb_flush_log_at_trx_commit同时设置为1,每次数据库写操作都会持久化binlog与redo log到磁盘上,保证数据的持久性。
开启VSR(virtual sync replication),保证主从能实时一致。
开启Group Commit,以及从库的并行复制,提升主从性能。
第2点里的VSR,这个是网易MySQL分支InnoSQL的一个特性,InnoSQL在官方半同步复制(semi sync)基础上做了部分改进,改善了主库宕机时主从数据不一致问题,实现机制如图所示:
简单来说,MySQL5.5版本中官方semi sync是在binlog与redo都写完后再将binlog传输到从库,而vsr则是在binlog写完后与redolog写之前传输binlog,这样做的好处是可以避免事务日志提交后主库宕机恢复后数据幻读问题。(在官方MySQL5.7中这个问题得到解决,见rpl_semi_sync_master_wait_point参数解释)。
当然这样做也有缺点,事务需要等待数据传输到从库后再返还,肯定会增加一定的延迟时间,针对这个问题,优化方法就是第三点开启group commit。开启后多个事务的binlog一次性提交到磁盘跟传输至从库,这样可以减少磁盘fsync次数并提升吞吐量。
以下是sync_group (vsr+group commit) 与原生semi sync、 sync(vsr) 、async(不开启semi sync) 之间性能对比图,可以看到 vsr + group commit性能与异步复制几无差别:
同时为了从库及时同步数据,我们在从库上打开并行复制,主库上事务并行提交从库上也可以并行恢复,这样大并发写入下从库没有基本延时。
随着业务的暴涨,数据量规模及QPS也暴涨几百倍,经过多次扩容后,为了提升DDB性能及容量,我们将IM云底层DBN节点从RDS迁移到物理机,并且使用大量的SSD作为底层存储。迁出RDS后DDB底层节点便不再拥有高可用这一特性,为此我们自己开发了一套DDB底层节点监控与切换工具DDB Monitor,此时DB高可用架构图变成:
DDBMonitor可用于执行日常数据库扩容切换、故障切换、状态监控等工作。
故障切换模式下会定时(几秒) 做如下事情:
状态检测,包括检测DBN存活状态,主从复制关系,binlog位置点,semi状态等;
模拟数据写入,检查主库是否可写。
在判断MySQL主从何时可以切换方面,与其它开源工具可能有些不同,需要满足以下情况才可能触发故障切换:
DBN主节点无法连接,错误号为2000-3000间指定几个(避免maxconnection等服务端反回的错误号造成误判);
DBN主节点指定时间内重试多次仍无法写入;
从库接收到的binlog已经应用完成或者在若干秒时间内应用完成;
上一次数据库vsr(semi sync)状态正常或上一次从库收到的binglog落后主库若干字节内 (根据业务数据重要程度设置);
如果主库无法连接,从库show slave status中Slave_IO_Running状态需为NO (从库与DDB Monitor工具同时监控主库是否宕机,避免脑裂问题);
从库Slave_SQL_Running状态需为 Yes。
其中条件1与条件2需要满足至少1者。 4中表示如果对主从一致性要求很高需要满足上次检测vsr(semi sync)正常才能切换,而如果可以容忍一定的数据丢失那么可以设置检测上次主从同步binlog差值在指定范围内即可切换。
故障切换后,SQL Proxy收到Master消息会重新建立到正确DBN的连接,主库宕机情况下基本可以在秒级别完成切换。
当然除了上面这些说的这些部署上保障高可用外之外,加强数据库设计与监控也是保障数据库稳定运行非常重要的一环。
数据库设计方面的措施主要有:
按照数据库设计规范进行表、SQL设计。表设计尽量精简,从数据访问角度设计表结构,在范式与反范式间要做合理的取舍;
数据请求尽量精简快,并减少跨节点访问,提升数据库真正的服务时间;
高频查询需要添加缓存,用户配置、群信息配置等少更新高访问请求走要缓存;
对数据一致性要求不高以及数据分析统计类的请求放到从库查询;
非核心功能、核心但数量少频次低模块走RDS,避免相互影响;
与应用合作,添加对DB冲击较大业务场景(比如聊天室)提供限流支持。
数据库监控方面我们主要做了如下以下几个方面:
DDB各个组件的网络、系统层面通用性指标监控;
SQL Proxy、DDB Master jvmgc信息、连接数、cpu、请求量、响应时间内存使用率日志等监控;
DBN节点(MySQL) Global status、processlist、innodb engine status、slowlog、数据增长率、表分区、文件句柄等监控;
数据运维平台上报表展示基于海量监控数据下通过一定算法得到数据库容量、运行状态、重要指标不同时间同比环比,风险点分析提示,风险SQL指示等。
一套DDB内通常包含几百个维度的指标监控及几十个维度的报警项。
●●●
多机房高可用实践
在过往的运维经历中,我们遇到过机柜掉电、机房大面积故障等事情,这种情况的发生会严重影响产品可用性。所以对于云信等重要产品,单机房高可用显然无法满足业务追求
多机房是个非常复杂的工程,不仅需要在部署上有多机房部署,在应用层面也需要支持多机房架构,虽然我们在产品发展初期就开始了多机房高可用建设,但到目前我们并没有完全做到自动化故障切换。
这里介绍下我们做的工作也是拍砖引玉,希望大家提出宝贵意见。
我们多机房高可用主要做到的工作:
备机房距主机房至少需隔两百公里距离,机房间必须有专线;
服务入口多机房,客户端请求根据流量配置转发到不同机房服务器;
应用与依赖组件多机房高可用部署(MQ、Hbase、对象存储服务等),部分组件需要应用双写多机房,比如Hbase、对象存储的写入等;
应用访问数据服务通过配置管理服务(DISCONF)获取,数据库与缓存通过使用功能(MySQL)或复制工具(缓存) 做跨机房数据复制;
监控多机房组件的可用性,PE与DBA部署好自动化切换工具;
确定基于binlog与应用日志的重要数据校验与补偿机制。
最后数据库高可用架构图:
人工切换始终会存在一定的延时,不过我们运维部强大的运维协作工具Stone支持移动端执行服务器命令,可以随时随地执行切换操作:
●●●
QA环节
Q1:有什么好的方案能在保证业务不中断的情况下实现跨机房大数据库迁移,在这过程中又如何保证数据的实时性呢?
A1: 数据库的实时性 可以有专线网络 + DB复制 来保障, 不终端服务实现跨机房的话 就需要系统相关的所有组件都支持跨机房高可用,并且需要实现自动化切换。补充一点, 跨机房服务部终端,会牺牲一定的数据一致性。需要补充的是,跨机房的服务部终端,会牺牲一定的数据一致性。
Q2:请问你们都有哪些自己研发的模块开源呢?很想学习下。
A2:网易InnoSQL是开源的,另外redis复制迁移工具 redis-migration也是开源的。
Q3:关系型数据库MySQL很流行,但是也有不足,我们最近在考虑有没有替换的方案。能否将它和其他的对比一下?你们是怎样做的选择?
A3:首先我觉得最好是选择你最熟悉的,能搞定的数据库。GitLab数据丢失事故 我认为很大的原因是因为他们的工程师对postgresql 不是很懂。另外MySQL发展其实非常快的,5.7 有很多非常好的特性,很多东西都借鉴了Oracle。
Q4:你们有什么开源的跨机房数据实时同步工具吗。
A4:我们网易内部有一套自己开发的数据复制工具DTS,目前还没有开源, 缓存复制工具有开源是 redis-migration,GitHub 上大家可以搜一下。
Q5:你们的数据访问高峰是什么时候呢?还是说一直比较平缓?还有,有没有大规模迁移数据库的经历,可以讲一讲吗?
A5:业务肯定有高峰低估的,一般晚上黄金时段是高峰期,凌晨是低谷。数据迁移的话其实做好工具后,数据大小量没有太大的差别,数据量大的话需要做限流。
Q6:从技术上选择MySQL和PG有什么区别?选择他们的时候你们是选了最熟悉的还是做了技术选型的调研?
A6:我们选择了最熟悉并且最适合我们的,PG跟MySQL都非常优秀,性能上也差不多。
Q7:能不能讲讲上次大规模故障的事情?多长时间内完成恢复?有哪些措施?数据如何备份?
A7: 故障恢复通常需要做好预案, 比如当你无法做到自动化切换的时候,就需要有一套切换的脚本,另外故障切换后通常需要做好一定的限流,不能切完再挂。数据备份方面:我们一套数据库备份系统, 数据库的备份会备份到存储服务上。
Q8:你们的采用分布式数据库与单节点数据库能完全兼容吗?
A8:大部分都能兼容,少数极端的case不兼容。
Q9:你们线上业务单表数据量能去到多少?是如何对这些表进行优化?
A9:一般我们都会分表, 一张大表可能有几十到几百张字表,百亿级表很多的,比如我们的消息表。表优化: 1 将历史数据迁移到离线数据库 2 精确好字段长度 3 尽量以primary key 或者联合索引去访问表。
Q10:为什么不在sql proxy层使用mycat?最近使用了mycat感觉还不错
A10:SQL Proxy跟我们DDB各组件是集成在一起的, DDB是2006年开始研发的,比市面上任何一款分库分表工具都悠久,我们对比过SQL Proxy跟mycat, 各有优缺点。
——【特别推荐】——